﻿#include "raw.h"
#include "mblock.h"
#include "debug.h"
#include "pktbuf.h"
#include "ipv4.h"
#include "socket.h"
#include "netif.h"
#include "tools.h"

static raw_t raw_tbl[RAW_MAX_NR]; // 存放raw类型的socket
static mblock_t raw_mblock;       // 内存管理器
static nlist_t raw_list;

#if DBG_DISP_ENABLED(DBG_RAW_LEVEL)
    static void display_raw_list()
    {
        plat_printf("-----------------raw_list-----------------\n");
        nlist_node_t *p;
        int index = 0;
        nlist_for_each(p, &raw_list){
            plat_printf("================================\n");
            raw_t *raw = (raw_t *)nlist_entry(sock_t, node, p);
            plat_printf("[%d]:\n", index++);
            dbg_dump_ipaddr("local_ip:", &raw->base.local_ipaddr);
            dbg_dump_ipaddr("remote_ip", &raw->base.remote_ipaddr);
            plat_printf("================================\n");
        }
        plat_printf("-----------------------------------------\n");
    }
#else
    #define display_raw_list()
#endif

/**
 * @brief raw初始化
 */
net_err_t raw_init()
{
    DBG_INFO(DBG_RAW_LEVEL, "raw init begin!");

    nlist_init(&raw_list);
    mblock_init(&raw_mblock, raw_tbl, sizeof(raw_t), RAW_MAX_NR, NLOCKER_NONE);

    DBG_INFO(DBG_RAW_LEVEL, "raw init end!");
    return NET_ERR_OK;
}

/**
 * @brief raw类型socket发送数据时调用的函数
 */
static net_err_t raw_sendto(struct _sock_t *s, const void *buf, size_t len, int flags,
                            const struct x_sockaddr *dest, x_socklen_t dest_len, ssize_t *result_len)
{
    pktbuf_t *pktbuf = pktbuf_alloc((u_int)len);
    if (!pktbuf)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "alloc pktbuf size:%d falied!", len);
        return NET_ERR_FULL;
    }

    net_err_t err = pktbuf_write(pktbuf, (const uint8_t *)buf, (int)len);
    if (err < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "write buf failed in raw sendto!");
        goto end_send_to;
    }

    ipaddr_t dest_ipaddr;
    const struct x_sockaddr_in *sockaddr = (const struct x_sockaddr_in *)dest;
    dest_ipaddr = ipaddr_from_buf(sockaddr->sin_addr.add_array, IPADDR_V4);
    if (!ipaddr_is_any(&s->remote_ipaddr) && !ipaddr_is_equal(&s->remote_ipaddr, &dest_ipaddr))
    {
        DBG_ERROR(DBG_RAW_LEVEL, "socket's remote ipaddr doesn't equal to dest ipaddr!");
        err = NET_ERR_MEM;
        goto end_send_to;
    }

    // netif_t *default_netif = netif_get_default();
    // err = ipv4_out(s->protocol, &dest_ipaddr, &default_netif->ipaddr, pktbuf);
    err = ipv4_out(s->protocol, &dest_ipaddr, &s->local_ipaddr, pktbuf);
    if (err < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "send pkt by ipv4 failed!");
        goto end_send_to;
    }

    *result_len = (ssize_t)len;
    return NET_ERR_OK;

end_send_to:
    pktbuf_free(pktbuf);
    return NET_ERR_SYS;
}

/**
 * @brief raw类型socket接收数据时调用的函数
 */
static net_err_t raw_recvfrom(struct _sock_t *s, void *buf, size_t len, int falgs,
                       struct x_sockaddr *dest, x_socklen_t *dest_len, ssize_t *result_len)
{
    raw_t *raw = (raw_t *)s;
    nlist_node_t *first = nlist_remove_first(&raw->recv_list);
    if(!first)
    {
        *result_len = 0;
        return NET_ERR_NEEDWAIT;
    }

    pktbuf_t *pktbuf = (pktbuf_t *)nlist_entry(pktbuf_t, node, first);
    ipv4_hdr_t *ipv4_hdr = (ipv4_hdr_t *)pktbuf_data(pktbuf);
    struct x_sockaddr_in *addr = (struct x_sockaddr_in *)dest;
    *dest_len = sizeof(struct x_sockaddr_in);
    plat_memset(addr, 0, sizeof(struct x_sockaddr_in));
    addr->sin_family = AF_INET;
    addr->sin_port = 0;
    addr->sin_len = IPV4_ADDR_SIZE;
    plat_memcpy(&addr->sin_addr, ipv4_hdr->src_ip, IPV4_ADDR_SIZE);

    int read_size = len > pktbuf->total_size ? pktbuf->total_size : (int)len;
    pktbuf_reset_acc(pktbuf);
    net_err_t err = pktbuf_read(pktbuf, buf, read_size, read_size);
    if(err < NET_ERR_OK){
        DBG_ERROR(DBG_RAW_LEVEL, "read pktbuf failed in raw recv!");
        pktbuf_free(pktbuf);
        return NET_ERR_SYS;
    }

    pktbuf_free(pktbuf);
    *result_len = read_size;
    return NET_ERR_OK;
}

/**
 * @brief raw类型socket调用的bind接口
 */
static net_err_t raw_bind(struct _sock_t *s, const struct x_sockaddr *addr, x_socklen_t addrlen)
{
    const struct x_sockaddr_in *bind_addr = (const struct x_sockaddr_in *)addr;
    ipaddr_t bind_ipaddr;
    bind_ipaddr.q_addr = bind_addr->sin_addr.s_addr;
    int bind_port = x_ntohs(bind_addr->sin_port);
    return sock_bind(s, &bind_ipaddr, bind_port);
}

/**
 * @brief raw类型socket调用的close接口
 */
static net_err_t raw_close(struct _sock_t *sock){
    raw_t *raw = (raw_t *)sock;
    
    // socket链表中移除该socket
    nlist_remove(&raw_list, &sock->node);
    //清除socket中的缓存
    nlist_node_t *first_node;
    while(first_node = nlist_remove_first(&raw->recv_list)){
        pktbuf_t *pktbuf = (pktbuf_t *)nlist_entry(pktbuf_t, node, first_node);
        pktbuf_free(pktbuf);
    }
    // 释放信号量
    sock_uninit(sock);
    // 释放socket
    mblock_free(&raw_mblock, raw);

    display_raw_list();
    return NET_ERR_OK;
}

/**
 * @brief 创建raw类型的socket
 */
sock_t *raw_create(int family, int protocol)
{
    const static sock_ops_t ops = {
        .sendto = raw_sendto,
        .send = sock_send,
        .recvfrom = raw_recvfrom,
        .recv = sock_recv,
        .connect = sock_connect,
        .bind = raw_bind,
        .close = raw_close};
    raw_t *raw = (raw_t *)mblock_alloc(&raw_mblock, DELIVER_NO_WAITTIME);
    if (!raw)
    {
        DBG_WARNING(DBG_RAW_LEVEL, "alloc raw failed!");
        return NULL;
    }

    nlist_init(&raw->recv_list);
    net_err_t err = sock_init(&raw->base, family, protocol, &ops);
    if (err < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "sock init failed in raw create!");
        mblock_free(&raw_mblock, raw);
        return NULL;
    }

    // raw类型socket接收数据时需要等待
    raw->base.recv_wait = &raw->recv_wait;
    if (sock_wait_init(raw->base.recv_wait) < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "recv wait init failed!");
        mblock_free(&raw_mblock, raw);
        sock_uninit(&raw->base);
        return NULL;
    }

    nlist_insert_last(&raw_list, &raw->base.node);
    display_raw_list();
    return (sock_t *)raw;
}

/**
 * @brief 查找指定的socket
 * @param src 收到的包的源ip地址
 * @param dst 收到的包的目的ip地址
 * @param protocol 收到的包使用的协议类型
 */
static raw_t *raw_find(const ipaddr_t *src, const ipaddr_t *dst, int protocol)
{
    nlist_node_t *p;
    nlist_for_each(p, &raw_list)
    {
        raw_t *raw = (raw_t *)nlist_entry(sock_t, node, p);
        if (!raw->base.protocol && raw->base.protocol != protocol)
        {
            continue;
        }
        if (!ipaddr_is_any(&raw->base.remote_ipaddr) && !ipaddr_is_equal(&raw->base.remote_ipaddr, src))
        {
            continue;
        }
        if (!ipaddr_is_any(&raw->base.local_ipaddr) && !ipaddr_is_equal(&raw->base.local_ipaddr, dst))
        {
            continue;
        }

        return raw;
    }

    display_raw_list();
    return NULL;
}

/**
 * @brief 处理收到的包
 * @param buf 收到的数据包
 */
net_err_t raw_in(pktbuf_t *buf)
{
    // 获取数据包的源和目的地址
    ipaddr_t src_addr;
    ipaddr_t dst_addr;
    pktbuf_reset_acc(buf);
    ipv4_pkt_t *ipv4_pkt = (ipv4_pkt_t *)pktbuf_data(buf);
    if (pktbuf_set_cont(buf, sizeof(ipv4_hdr_t)) < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "set buf cont:%d failed!", sizeof(ipv4_pkt_t));
        return NET_ERR_SYS;
    }
    src_addr = ipaddr_from_buf(ipv4_pkt->hdr.src_ip, IPADDR_V4);
    dst_addr = ipaddr_from_buf(ipv4_pkt->hdr.dst_ip, IPADDR_V4);

    // 根据源和目的ip以及协议类型查找指定的socket
    raw_t *raw = raw_find(&src_addr, &dst_addr, ipv4_pkt->hdr.protocol);
    if(!raw){
        DBG_WARNING(DBG_RAW_LEVEL, "can't find suitable raw socket!");
        return NET_ERR_UNREACH;
    }

    if(nlist_count(&raw->recv_list) < RAW_MAX_RECV)
    {
        nlist_insert_last(&raw->recv_list, &buf->node);
        sock_wakeup(&raw->base, SOCK_WAIT_READ, NET_ERR_OK);
    }
    else
    {
        DBG_WARNING(DBG_RAW_LEVEL, "the raw recv list is full!");
        return NET_ERR_FULL; // 处理失败，交给下层释放包
    }

    return NET_ERR_OK;
}
